package me.flyray.bsin.server.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;
import com.github.binarywang.wxpay.service.WxPayService;
import lombok.extern.slf4j.Slf4j;
import me.flyray.bsin.domain.entity.MerchantConfig;
import me.flyray.bsin.domain.entity.PayChannelConfig;
import me.flyray.bsin.domain.entity.Transaction;
import me.flyray.bsin.domain.enums.TransactionStatus;
import me.flyray.bsin.dubbo.invoke.BsinServiceInvoke;
import me.flyray.bsin.facade.service.MerchantConfigService;
import me.flyray.bsin.infrastructure.mapper.TransactionJournalMapper;
import me.flyray.bsin.infrastructure.mapper.TransactionMapper;
import me.flyray.bsin.infrastructure.biz.paychannel.PayChannelConfigBiz;
import me.flyray.bsin.payment.channel.wxpay.BsinWxPayServiceUtil;
import me.flyray.bsin.payment.channel.wxpay.WxServiceUtil;
import me.flyray.bsin.payment.enums.PayChannelInterfaceEnum;
import me.flyray.bsin.payment.enums.ProfitSharingTypeEnum;
import me.flyray.bsin.server.service.ProfitSharingService;
import me.flyray.bsin.thirdauth.wx.utils.WxRedisConfig;
import org.apache.shenyu.client.apidocs.annotations.ApiDoc;
import org.apache.shenyu.client.apidocs.annotations.ApiModule;
import org.apache.shenyu.client.springmvc.annotation.ShenyuSpringMvcClient;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/payCallback")
@ShenyuSpringMvcClient("/payCallback/**")
@ApiModule(value = "payCallback")
@Slf4j
public class PayCallbackController {

  @Autowired private BsinServiceInvoke bsinServiceInvoke;

  // 常量定义
  @Autowired BsinWxPayServiceUtil bsinWxPayServiceUtil;
  @Autowired private TransactionMapper transactionMapper;
  @Autowired private TransactionJournalMapper waasTransactionJournalMapper;


  @DubboReference(version = "${dubbo.provider.version}")
  private MerchantConfigService merchantConfigService;

  @Autowired private ProfitSharingService profitSharingService;
  @Autowired private PayChannelConfigBiz payChannelConfigBiz;

  /**
   * 微信支付回调处理（完全兼容 v2 和 v3，支持服务商、普通商户、特约商户）
   *
   * 支持的回调类型：
   * 1. 普通商户支付回调（v2/v3）
   * 2. 服务商子商户支付回调（v2/v3）
   * 3. 特约商户支付回调（v2/v3）
   * 4. 分账回调（v2/v3）
   *
   * 处理流程：
   * 1. 根据 outTradeNo 查询订单信息
   * 2. 获取支付渠道配置
   * 3. 解析回调数据（自动识别 v2/v3）
   * 4. 验证签名和更新交易状态
   * 5. 执行分账（如果配置了分账）
   * 6. 调用oms模块处理业务订单
   *
   * 参考：https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
   *
   * @param body 回调数据
   * @param outTradeNo 外部订单号
   * @return
   * @throws Exception
   */
  @PostMapping("/wxpay/{outTradeNo}")
  @ApiDoc(desc = "wxpay")
  public Object wxpay(
      @RequestBody(required = false) String body,
      @PathVariable("outTradeNo") String outTradeNo,
      @RequestHeader Map<String, String> headers)
      throws Exception {
    WxPayOrderNotifyResult result = null;
    WxPayNotifyV3Result wxPayNotifyV3Result = null;
    WxPayNotifyV3Result.DecryptNotifyResult v3Result = null;
    try {
      log.info("微信支付回调开始处理，outTradeNo: {}", outTradeNo);
      log.info("回调数据body: {}", body);
      log.info("回调头headers: {}", headers);

      // 1、根据 outTradeNo 查询订单信息
      Transaction transaction =
          transactionMapper.selectOne(
              new LambdaQueryWrapper<Transaction>().eq(Transaction::getOutOrderNo, outTradeNo));

      if (transaction == null) {
        log.error("未找到对应的交易订单，outTradeNo: {}", outTradeNo);
        return WxPayNotifyResponse.fail("订单不存在");
      }

      log.info("查询到交易订单: {}", transaction);

      // 2、根据订单信息查询支付渠道配置
      String payChannelConfigNo = transaction.getPayChannelConfigNo();
      if (payChannelConfigNo == null || payChannelConfigNo.isEmpty()) {
        log.error("交易订单未关联支付渠道配置，outTradeNo: {}", outTradeNo);
        return WxPayNotifyResponse.fail("支付渠道配置不存在");
      }

      log.info("支付渠道配置编号: {}", payChannelConfigNo);

      // 3、获取微信支付服务（支持 v2 和 v3）
      WxServiceUtil wxServiceUtil = payChannelConfigBiz.getWxServiceWrapper(payChannelConfigNo);
      WxPayService wxPayService = wxServiceUtil.getWxPayService();

      // 获取支付渠道配置信息
      PayChannelConfig payChannelConfig = payChannelConfigBiz.getPayChannelConfig(payChannelConfigNo);
      if (payChannelConfig == null) {
        log.error("未找到支付渠道配置，payChannelConfigNo: {}", payChannelConfigNo);
        return WxPayNotifyResponse.fail("支付渠道配置不存在");
      }

      Map<String, Object> requestMap = new HashMap<>();

      // 4、智能解析微信支付回调数据（根据配置自动识别版本和商户模式）
      if ("V3".equals(wxServiceUtil.getApiVersion())) {
        log.info("微信支付V3回调");
        SignatureHeader header = SignatureHeader.builder()
                .timeStamp(headers.get("wechatpay-timestamp"))
                .nonce(headers.get("wechatpay-nonce"))
                .signature(headers.get("wechatpay-signature"))
                .serial(headers.get("wechatpay-serial"))
//                .signType(headers.get("Wechatpay-Signature-Type"))
                .build();
        wxPayNotifyV3Result = wxPayService.parseOrderNotifyV3Result(body, header);
        log.info("微信回调结果：{}", wxPayNotifyV3Result.getResult().toString());
        v3Result = wxPayNotifyV3Result.getResult();
        requestMap.put("resultCode", v3Result.getTradeState());
        requestMap.put("orderNo", v3Result.getOutTradeNo());
//        requestMap.put("cashFee", v3Result.getAmount().getPayerFee());
        requestMap.put("payId", v3Result.getTransactionId());
        requestMap.put("totalFee", v3Result.getAmount().getPayerTotal());
//        requestMap.put("timeEnd", v3Result.get());
        requestMap.put("openid", v3Result.getPayer() != null ? v3Result.getPayer().getOpenid() : null);
//        V3接口验证微信支付通知参数
      } else {
        log.info("微信支付V2回调");
        result = wxPayService.parseOrderNotifyResult(body);
        log.info("回调结果: {}", JSONObject.toJSONString(result));
        requestMap.put("resultCode", result.getResultCode());
        requestMap.put("orderNo", result.getOutTradeNo());
        requestMap.put("cashFee", result.getCashFee());
        requestMap.put("payId", result.getTransactionId());
        requestMap.put("totalFee", result.getTotalFee());
        requestMap.put("timeEnd", result.getTimeEnd());
        requestMap.put("openid", result.getOpenid());
      }
      
      // 验证回调解析结果
      if (result == null && v3Result == null) {
        log.error("微信支付回调解析失败，无法识别回调格式");
        return WxPayNotifyResponse.fail("回调解析失败");
      }
      
      // 添加商户模式信息
      requestMap.put("merchantPayMode", payChannelConfig.getMerchantPayMode());
      requestMap.put("payWay", payChannelConfig.getPayWay());
      requestMap.put("bizRoleAppId", payChannelConfig.getBizRoleAppId());
      requestMap.put("bizRoleTypeNo", payChannelConfig.getBizRoleTypeNo());

      // 4、验证更新交易状态
      Transaction updatedTransaction = updateTransactionStatus(result, v3Result);
      if (updatedTransaction == null) {
        String orderNo = result != null ? result.getOutTradeNo() : v3Result.getOutTradeNo();
        log.warn("未找到对应的交易记录，订单号：{}", orderNo);
        return WxPayNotifyResponse.fail("未找到交易记录");
      }

      // 6、支付分账阶段（独立事务）
      String resultCode = result != null ? result.getResultCode() : v3Result.getTradeState();
      if ("SUCCESS".equals(resultCode)) {
        // 检查是否为分账回调
        if (isProfitSharingCallback(result, v3Result)) {
          log.info("检测到分账回调，处理分账结果");
          handleProfitSharingCallback(result, v3Result, updatedTransaction);
        } else {
          // 普通支付回调，执行分账
          executePaymentAllocationSafely(updatedTransaction);
        }
      }

      // 6、异步调用（泛化调用解耦）订单完成方法统一处理： 根据订单类型后续处理
      bsinServiceInvoke.genericInvoke("UnifyOrderService", "completePay", "dev", requestMap);

      // 7、异步锁客处理
      lockCustomerHandler(updatedTransaction);

      String orderNo = result != null ? result.getOutTradeNo() : v3Result.getOutTradeNo();
      log.info("微信支付回调处理完成，订单号: {}", orderNo);

    } catch (Exception e) {
      String orderNo = result != null ? result.getOutTradeNo() : (v3Result != null ? v3Result.getOutTradeNo() : "未知");
      log.error(
          "微信支付回调处理失败，outTradeNo: {}, 订单号: {}",
          outTradeNo != null ? outTradeNo : "未知",
          orderNo,
          e);
      return WxPayNotifyResponse.fail("支付失败");
    }
    return WxPayNotifyResponse.success("success");
  }


  /** 1、判断用户是否被商家锁客 2、没有则将客户锁定给商家，成为门店的锁客会员 */
  private void lockCustomerHandler(Transaction transaction) {
    Map<String, Object> requestMap = new HashMap<>();
    requestMap.put("customerNo", transaction.getFromAddress());
    requestMap.put("storeNo", transaction.getToAddress());
    bsinServiceInvoke.genericInvoke("MemberService", "lockCustomer", "dev", requestMap);
  }

  /**
   * 安全执行支付分账，包含完整的异常处理
   *
   * @param transaction 交易信息
   * @return PaymentAllocationResult 支付分账结果
   */
  private PaymentAllocationResult executePaymentAllocationSafely(Transaction transaction) {
    final String serialNo = transaction.getSerialNo();

    try {
      // 检查是否需要分账
      if (!shouldExecuteProfitSharing(transaction)) {
        log.info("无需分账，跳过支付分账，交易号：{}", serialNo);
        return new PaymentAllocationResult(false, null);
      }

      // 执行分账
      var result =
          profitSharingService.executeProfitSharing(
              transaction, PayChannelInterfaceEnum.WXPAY.getCode());

      if (result.isSuccess()) {
        log.info("支付分账执行成功，交易号：{}", serialNo);
        return new PaymentAllocationResult(true, null);
      } else {
        log.warn("支付分账执行失败，交易号：{}，错误信息：{}", serialNo, result.getMessage());
        return new PaymentAllocationResult(false, result.getMessage());
      }

    } catch (Exception e) {
      log.error("支付分账执行失败，交易号：{}", serialNo, e);
      return new PaymentAllocationResult(false, e.getMessage());
    }
  }

  /** 判断是否需要执行分账 */
  private boolean shouldExecuteProfitSharing(Transaction transaction) {
    // 检查交易金额是否满足分账条件
    if (transaction.getTxAmount() == null
        || transaction.getTxAmount().compareTo(BigDecimal.ZERO) <= 0) {
      return false;
    }

    // 检查是否配置了分账
    MerchantConfig merchantConfig = getMerchantConfig(transaction);
    if (merchantConfig == null || merchantConfig.getProfitSharingRate() == null) {
      return false;
    }

    // 检查分账类型
    String profitSharingType = transaction.getProfitSharingType();
    if (ProfitSharingTypeEnum.BY_ORDER.getCode().equals(profitSharingType)) {
      // 订单类型：检查是否有预设分账金额
      return transaction.getProfitSharingAmount() != null
          && transaction.getProfitSharingAmount().compareTo(BigDecimal.ZERO) > 0;
    } else if (ProfitSharingTypeEnum.BY_PRODUCT.getCode().equals(profitSharingType)) {
      // 商品类型：检查分账比例
      return merchantConfig.getProfitSharingRate().compareTo(BigDecimal.ZERO) > 0;
    }

    return false;
  }

  /** 获取商户配置 */
  private MerchantConfig getMerchantConfig(Transaction transaction) {
    try {
      Map<String, Object> requestMap = new HashMap<>();
      // 使用toAddress作为商户号，因为Transaction中toAddress存储的是商户号
      requestMap.put("merchantNo", transaction.getToAddress());
      requestMap.put("tenantId", transaction.getTenantId());
      return merchantConfigService.getDetail(requestMap);
    } catch (Exception e) {
      log.error("获取商户配置失败，商户号：{}", transaction.getToAddress(), e);
      return null;
    }
  }
  /**
   * 判断是否为分账回调
   *
   * @param result V2回调结果
   * @param v3Result V3回调结果
   * @return 是否为分账回调
   */
  private boolean isProfitSharingCallback(WxPayOrderNotifyResult result, WxPayNotifyV3Result.DecryptNotifyResult v3Result) {
    try {
      if (result != null) {
        // V2回调 - 检查是否为分账回调
        // 分账回调通常包含分账相关的字段，如分账单号等
        String outTradeNo = result.getOutTradeNo();
        String transactionId = result.getTransactionId();
        
        // 可以通过分账单号前缀或其他标识判断
        return outTradeNo != null && (outTradeNo.startsWith("PS") || outTradeNo.contains("profit_sharing"));
        
      } else if (v3Result != null) {
        // V3回调 - 检查是否为分账回调
        String outTradeNo = v3Result.getOutTradeNo();
        String transactionId = v3Result.getTransactionId();
        
        // V3分账回调通常包含分账相关的字段
        return outTradeNo != null && (outTradeNo.startsWith("PS") || outTradeNo.contains("profit_sharing"));
      }
      
      return false;
    } catch (Exception e) {
      log.error("判断分账回调类型失败", e);
      return false;
    }
  }

  /**
   * 处理分账回调
   *
   * @param result V2分账回调结果
   * @param v3Result V3分账回调结果
   * @param transaction 交易信息
   */
  private void handleProfitSharingCallback(WxPayOrderNotifyResult result, WxPayNotifyV3Result.DecryptNotifyResult v3Result, Transaction transaction) {
    try {
      String resultCode = null;
      String errorMsg = null;
      String orderId = null;
      String transactionId = null;
      
      if (result != null) {
        // V2回调
        resultCode = result.getResultCode();
        errorMsg = result.getReturnMsg();
        orderId = result.getOutTradeNo();
        transactionId = result.getTransactionId();
      } else if (v3Result != null) {
        // V3回调
        resultCode = v3Result.getTradeState();
        errorMsg = v3Result.getTradeStateDesc();
        orderId = v3Result.getOutTradeNo();
        transactionId = v3Result.getTransactionId();
      }
      
      log.info("处理分账回调，交易号: {}, 分账结果: {}, 分账单号: {}", 
               transaction.getSerialNo(), resultCode, orderId);

      // 更新分账状态
      if ("SUCCESS".equals(resultCode)) {
        transaction.setProfitSharingStatus(true);
        log.info("分账成功，交易号: {}", transaction.getSerialNo());
        
        // 记录分账成功日志
        recordProfitSharingSuccess(transaction, orderId, transactionId);
        
      } else {
        transaction.setProfitSharingStatus(false);
        log.warn("分账失败，交易号: {}, 错误信息: {}", transaction.getSerialNo(), errorMsg);
        
        // 记录分账失败日志
        recordProfitSharingFailure(transaction, orderId, errorMsg);
      }

      // 更新交易状态
      updateTransactionStatus(transaction);

    } catch (Exception e) {
      log.error("处理分账回调失败，交易号: {}", transaction.getSerialNo(), e);
    }
  }

  /** 更新交易流水和交易状态
   *
   * */
  @Transactional(rollbackFor = Exception.class)
  protected Transaction updateTransactionStatus(WxPayOrderNotifyResult result, WxPayNotifyV3Result.DecryptNotifyResult v3Result) {
    String outTradeNo;
    String resultCode;
    
    if (result != null) {
      // V2回调
      outTradeNo = result.getOutTradeNo();
      resultCode = result.getResultCode();
    } else if (v3Result != null) {
      // V3回调
      outTradeNo = v3Result.getOutTradeNo();
      resultCode = v3Result.getTradeState();
    } else {
      log.error("回调结果为空，无法更新交易状态");
      return null;
    }
    
    // 根据 WaasTransactionNo 查询交易订单并更新交易状态
    Transaction waasTransaction =
        transactionMapper.selectOne(
            new LambdaQueryWrapper<Transaction>()
                .eq(Transaction::getOutOrderNo, outTradeNo));
    if (waasTransaction == null) {
      return null;
    }

    // 更新交易流水
    if ("SUCCESS".equals(resultCode)) {
      waasTransaction.setTransactionStatus(TransactionStatus.SUCCESS.getCode());
      waasTransactionJournalMapper.updateTransferStatus(
          waasTransaction.getSerialNo(), TransactionStatus.SUCCESS.getCode());
    } else {
      waasTransaction.setTransactionStatus(TransactionStatus.FAIL.getCode());
      waasTransactionJournalMapper.updateTransferStatus(
          waasTransaction.getSerialNo(), TransactionStatus.FAIL.getCode());
    }
    transactionMapper.updateById(waasTransaction);
    return waasTransaction;
  }

  /** 更新交易状态(分账完成后)
   *
   * */
  @Transactional(rollbackFor = Exception.class)
  protected void updateTransactionStatus(Transaction transaction) {
    // 分账完成后，更新交易状态为成功
    transaction.setTransactionStatus(TransactionStatus.SUCCESS.getCode());
    // 更新交易流水状态
    waasTransactionJournalMapper.updateTransferStatus(
        transaction.getSerialNo(), TransactionStatus.SUCCESS.getCode());
    // 更新交易记录
    transactionMapper.updateById(transaction);
    log.info("分账完成，交易状态已更新为成功，交易号：{}", transaction.getSerialNo());
  }

  /**
   * 记录分账成功日志
   */
  private void recordProfitSharingSuccess(Transaction transaction, String orderId, String transactionId) {
    try {
      log.info("分账成功记录，交易号: {}, 分账单号: {}, 微信订单号: {}", 
               transaction.getSerialNo(), orderId, transactionId);
      
      // TODO: 可以在这里添加分账成功后的业务逻辑
      // 比如：发送通知、更新统计等
      
    } catch (Exception e) {
      log.error("记录分账成功日志失败，交易号: {}", transaction.getSerialNo(), e);
    }
  }

  /**
   * 记录分账失败日志
   */
  private void recordProfitSharingFailure(Transaction transaction, String orderId, String errorMsg) {
    try {
      log.warn("分账失败记录，交易号: {}, 分账单号: {}, 错误信息: {}", 
               transaction.getSerialNo(), orderId, errorMsg);
      
      // TODO: 可以在这里添加分账失败后的业务逻辑
      // 比如：发送告警、重试机制等
      
    } catch (Exception e) {
      log.error("记录分账失败日志失败，交易号: {}", transaction.getSerialNo(), e);
    }
  }

  /** 支付分账结果封装类 */
  private static class PaymentAllocationResult {
    private final boolean success;
    private final String errorMessage;

    public PaymentAllocationResult(boolean success, String errorMessage) {
      this.success = success;
      this.errorMessage = errorMessage;
    }

    public boolean isSuccess() {
      return success;
    }

    public String getErrorMessage() {
      return errorMessage;
    }
  }

  /** 支付宝支付回调接口（预留） */
  @PostMapping("/alipay/{outTradeNo}")
  @ApiDoc(desc = "alipay")
  public Object alipay(
      @RequestBody(required = false) String body, @PathVariable("outTradeNo") String outTradeNo)
      throws Exception {
    // TODO: 实现支付宝支付回调处理
    log.info("支付宝支付回调，outTradeNo: {}", outTradeNo);
    return "success";
  }

  /** 银联支付回调接口（预留） */
  @PostMapping("/unionpay/{outTradeNo}")
  @ApiDoc(desc = "unionpay")
  public Object unionpay(
      @RequestBody(required = false) String body, @PathVariable("outTradeNo") String outTradeNo)
      throws Exception {
    // TODO: 实现银联支付回调处理
    log.info("银联支付回调，outTradeNo: {}", outTradeNo);
    return "success";
  }
}
// https://5p33041l87.vicp.fun/callback/payCallback/wxpay/1951680965604675584/wx6225d2d623ff1b40/wx6225d2d623ff1b40/1/WX_LITE
